package com.conversationboard.controller.search;

import java.io.IOException;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.queryParser.ParseException;

import com.conversationboard.config.Configuration;
import com.conversationboard.fulltext.search.Search;
import com.conversationboard.fulltext.search.SortOrder;
import com.conversationboard.fulltext.search.hit.MessageHit;
import com.conversationboard.fulltext.search.hit.ThreadHit;
import com.conversationboard.model.User;

@WebServlet(name="FullTextSearchControllerServlet", urlPatterns="/FullTextSearchControllerServlet")
public class FullTextSearchControllerServlet extends HttpServlet {

	private static final long serialVersionUID = -8689249702195475099L;


	private boolean dateValid(String date) {

		if (date == null) {
			return false;
		}

		if (date.matches("^[0-9]{4}-[0-9]{2}-[0-9]{2}$")) {
			return true;
		} else {
			return false;
		}
	}


	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		this.doPost(request, response);
	}


	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

		response.setCharacterEncoding("UTF-8");
		request.setCharacterEncoding("UTF-8");

		try {

			User user = getUser(request);

			if (request.getParameter("terms") == null || request.getParameter("terms") == "") {
				response.sendRedirect(Configuration.getInstance().getRoot() + "/Pages/Search/search.jsp");
				return;
			}

			String searchType = request.getParameter("searchtype");
			String terms = request.getParameter("terms").trim();
			int offset = Integer.parseInt(request.getParameter("offset"));
			int boardId = Integer.parseInt(request.getParameter("boardid"));
			String startDateText = request.getParameter("startdate").trim();
			String endDateText = request.getParameter("enddate").trim();
			String artefact = request.getParameter("artefact");
			String idType = request.getParameter("idtype");
			SortOrder sortOrder = SortOrder.valueOf(request.getParameter("sortorder"));

			/* If this is the first page, escape the query terms, otherwise don't or we'll do it again */

			if (offset == 0) {
				terms = Search.escapeQueryString(terms);
			}

			/* Forward the attributes on to the results page so that we can click next and resubmit to this page */

			forwardAttibutes(request, searchType, terms, offset, boardId, startDateText, endDateText, artefact, idType, sortOrder.toString());

			/* Check validity of dates and get them into date objects if valid */

			Date startDate = null;
			Date endDate = null;

			SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");

			if (this.dateValid(startDateText)) {
				startDate = formatter.parse(startDateText);
			}

			if (this.dateValid(endDateText)) {
				endDate = formatter.parse(endDateText);
			}

			RequestDispatcher dispatcher = getDispatcher(request, artefact);

			this.search(request, user, searchType, terms, boardId, startDate, endDate, offset, artefact, idType, sortOrder);

			dispatcher.forward(request, response);
			return;

		} catch (SQLException e) {
			throw new ServletException(e);
		} catch (ParseException e) {
			/* Swallow: expect to get a lot of duff input */
		} catch (java.text.ParseException e) {
			throw new ServletException(e);
		}

	}



	/** Actually perform the search and stick either a list of ThreadHit objects or a list of MessageHit objects into the response */

	private void search(HttpServletRequest request, User user, String searchType, String terms, int boardId, Date startDate, Date endDate, int offset, String artefact, String idType, SortOrder sortOrder) throws ParseException, java.text.ParseException, CorruptIndexException, IOException, SQLException {

		Search search = new Search();

		search.setStartDate(startDate);
		search.setEndDate(endDate);
		search.setBoardId(boardId);

		if (searchType.equalsIgnoreCase("text")) {

			/* Searching through basic thread or message info */

			if (artefact.equalsIgnoreCase("threads")) {
				List<ThreadHit> threadHits = search.searchThreads(user, terms, offset, Search.MAX_SEARCH_RESULTS_PER_PAGE, sortOrder);
				request.setAttribute("nextavailable", true);
				request.setAttribute("hits", threadHits);

			} else if (artefact.equalsIgnoreCase("messages")) {

				List<MessageHit> messageHits = search.searchMessages(user, terms, offset, Search.MAX_SEARCH_RESULTS_PER_PAGE, sortOrder);
				request.setAttribute("nextavailable", true);
				request.setAttribute("hits", messageHits);

			}

		} else if (searchType.equalsIgnoreCase("id")) {

			String queryString = "";

			if (idType.equalsIgnoreCase("loginid")) {
				queryString = "loginId: \"" + terms + "\"";
			} else if (idType.equalsIgnoreCase("displayname")) {
				queryString = "displayName: \"" + terms + "\"";
			}

			/* Searching for threads or messages by given users */

			if (artefact.equalsIgnoreCase("threads")) {
				List<ThreadHit> threadHits = search.searchThreads(user, queryString, offset, Search.MAX_SEARCH_RESULTS_PER_PAGE, sortOrder);
				request.setAttribute("nextavailable", true);
				request.setAttribute("hits", threadHits);
			} else if (artefact.equalsIgnoreCase("messages")) {
				List<MessageHit> messageHits = search.searchMessages(user, queryString, offset, Search.MAX_SEARCH_RESULTS_PER_PAGE, sortOrder);
				request.setAttribute("nextavailable", true);
				request.setAttribute("hits", messageHits);
			}
		}
	}


	private RequestDispatcher getDispatcher(HttpServletRequest request, String artefact) {
		RequestDispatcher dispatcher = null;

		if (artefact.equalsIgnoreCase("threads")) {
			dispatcher = request.getRequestDispatcher("/Pages/Search/thread-search-results.jsp");
		} else if (artefact.equalsIgnoreCase("messages")) {
			dispatcher = request.getRequestDispatcher("/Pages/Search/message-search-results.jsp");
		}
		return dispatcher;
	}


	private void forwardAttibutes(HttpServletRequest request, String searchType, String terms, int offset, int boardId, String startDateText, String endDateText, String artefact, String idType, String sortOrder) {

		request.setAttribute("searchtype", searchType);
		request.setAttribute("terms", terms);
		request.setAttribute("offset", offset + Search.MAX_SEARCH_RESULTS_PER_PAGE);
		request.setAttribute("startdate", startDateText);
		request.setAttribute("enddate", endDateText);
		request.setAttribute("artefact", artefact);
		request.setAttribute("idtype", idType);
		request.setAttribute("sortorder", sortOrder);
		request.setAttribute("boardid", boardId);

	}


	private User getUser(HttpServletRequest request) throws SQLException {

		User user = null;

		if (request.getUserPrincipal() == null) {
			user = User.getAnonymousUser();
		} else {
			user = User.get(request.getUserPrincipal().getName());
		}

		return user;
	}

}
